﻿namespace BM.Tools.WebControls.MForm.Controls.Helper
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Globalization;
    using System.Linq;
    using System.Reflection;
    using System.Web.UI;

    /// <summary>
    /// This class collects data from the control's properties <see cref="AttributePropertyAttribute" /> attributes
    /// and adds these attributes to the control
    /// </summary>
    public static class AttributeAttacher
    {
        private static Dictionary<Type, IEnumerable<AttributeStruct>> attributeForTypeDictionary = new Dictionary<Type, IEnumerable<AttributeStruct>>();

        /// <summary>
        /// Collects all properties with the AttributeProperty specified
        /// </summary>
        /// <param name="control">
        /// The control.
        /// </param>
        /// <returns>
        /// returns a dictionary with those attributes and property values
        /// </returns>
        public static Dictionary<string, object> GetJsonProperties(this Control control)
        {
            var dictionary = new Dictionary<string, object>();
            foreach (var attributeStruct in GetAttributesForType(control.GetType()))
            {                        
                var value = control.GetValue(attributeStruct.Info);
                if (value != null)
                {
                    dictionary.Add(attributeStruct.Attribute.Name, value);                        
                }                
            }

            return dictionary;
        }

        private static IEnumerable<AttributeStruct> GetAttributesForType(Type type)
        {
            if (!attributeForTypeDictionary.ContainsKey(type))
            {
                attributeForTypeDictionary[type] = CreateAttributesForType(type).ToArray();
            }

            return attributeForTypeDictionary[type];
        }

        private static IEnumerable<AttributeStruct> CreateAttributesForType(Type type)
        {
            foreach (var info in type.GetProperties())
            {
                var attribute = Attribute.GetCustomAttribute(info, typeof(AttributePropertyAttribute)) as AttributePropertyAttribute;
                if (attribute != null)
                {
                    yield return new AttributeStruct
                                     {
                                         Attribute = attribute, 
                                         Info = info
                                     };
                }
            }            
        }

        private static object GetValue(this Control control, PropertyInfo info)
        {
            object value = info.GetValue(control, null);
            if (value == null)
            {
                return null;
            }

            PropertyDescriptor descriptor = TypeDescriptor.GetProperties(control).Find(info.Name, false);
            if (descriptor.Attributes[typeof(UrlPropertyAttribute)] != null)
            {
                return control.ResolveClientUrl((string)value);
            }            
            
            if (descriptor.Attributes[typeof(UrlPropertyAttribute)] != null)
            {
                return descriptor.Converter.ConvertToString(null, CultureInfo.InvariantCulture, value);
            }

            return value;
        }

        private struct AttributeStruct
        {
            public AttributePropertyAttribute Attribute
            {
                get; 
                set; 
            }

            public PropertyInfo Info
            {
                get; 
                set; 
            }
        }
    }
}